// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <OpenGl_AspectsSprite.hxx>

#include <OpenGl_Context.hxx>
#include <OpenGl_PointSprite.hxx>
#include <OpenGl_TextureSet.hxx>

#include <Image_PixMap.hxx>
#include <Graphic3d_MarkerImage.hxx>
#include <TColStd_HArray1OfByte.hxx>

namespace
{
  static const TCollection_AsciiString THE_EMPTY_KEY;

  //! Draw inner point as filled rectangle
  static Handle(TColStd_HArray1OfByte) fillPointBitmap (const Standard_Integer theSize)
  {
    // draw inner point as filled rectangle
    const Standard_Integer        aNumOfBytes = (theSize / 8 + (theSize % 8 ? 1 : 0)) * theSize;
    Handle(TColStd_HArray1OfByte) aBitMap     = new TColStd_HArray1OfByte (0, aNumOfBytes - 1);
    for (Standard_Integer anIter = 0; anIter < aBitMap->Length(); ++anIter)
    {
      aBitMap->SetValue (anIter, 255);
    }
    return aBitMap;
  }
}

// Following Section relates to default markers

#define TEL_NO_OF_SIZES 13
#define TEL_PM_START_SIZE 1.0
#define TEL_PM_END_SIZE   7.0

struct PM_FONT_INFO
{
  float width, height;
  int   offset;
};
typedef PM_FONT_INFO* pm_font_info;

#define PM_PLUS_10_NUM  9*2
#define PM_PLUS_15_NUM  11*2
#define PM_PLUS_20_NUM  13*2
#define PM_PLUS_25_NUM  15*2
#define PM_PLUS_30_NUM  17*3
#define PM_PLUS_35_NUM  19*3
#define PM_PLUS_40_NUM  21*3
#define PM_PLUS_45_NUM  23*3
#define PM_PLUS_50_NUM  25*4
#define PM_PLUS_55_NUM  27*4
#define PM_PLUS_60_NUM  29*4
#define PM_PLUS_65_NUM  31*4
#define PM_PLUS_70_NUM  32*4

#define PM_STAR_10_NUM  9
#define PM_STAR_15_NUM  11*2
#define PM_STAR_20_NUM  13*2
#define PM_STAR_25_NUM  15*2
#define PM_STAR_30_NUM  17*2
#define PM_STAR_35_NUM  19*2
#define PM_STAR_40_NUM  21*3
#define PM_STAR_45_NUM  23*3
#define PM_STAR_50_NUM  25*3
#define PM_STAR_55_NUM  27*3
#define PM_STAR_60_NUM  29*4
#define PM_STAR_65_NUM  32*4
#define PM_STAR_70_NUM  32*4

#define PM_CIRC_10_NUM  7
#define PM_CIRC_15_NUM  9*2
#define PM_CIRC_20_NUM  9*2
#define PM_CIRC_25_NUM  11*2
#define PM_CIRC_30_NUM  13*2
#define PM_CIRC_35_NUM  15*2
#define PM_CIRC_40_NUM  17*3
#define PM_CIRC_45_NUM  19*3
#define PM_CIRC_50_NUM  21*3
#define PM_CIRC_55_NUM  23*3
#define PM_CIRC_60_NUM  25*4
#define PM_CIRC_65_NUM  27*4
#define PM_CIRC_70_NUM  29*4

#define PM_CROSS_10_NUM 7
#define PM_CROSS_15_NUM 9*2
#define PM_CROSS_20_NUM 11*2
#define PM_CROSS_25_NUM 13*2
#define PM_CROSS_30_NUM 15*2
#define PM_CROSS_35_NUM 17*3
#define PM_CROSS_40_NUM 19*3
#define PM_CROSS_45_NUM 21*3
#define PM_CROSS_50_NUM 23*3
#define PM_CROSS_55_NUM 25*4
#define PM_CROSS_60_NUM 27*4
#define PM_CROSS_65_NUM 32*4
#define PM_CROSS_70_NUM 32*4

#define PM_PLUS_10_OFT  0
#define PM_PLUS_15_OFT  PM_PLUS_10_OFT + PM_PLUS_10_NUM
#define PM_PLUS_20_OFT  PM_PLUS_15_OFT + PM_PLUS_15_NUM
#define PM_PLUS_25_OFT  PM_PLUS_20_OFT + PM_PLUS_20_NUM
#define PM_PLUS_30_OFT  PM_PLUS_25_OFT + PM_PLUS_25_NUM
#define PM_PLUS_35_OFT  PM_PLUS_30_OFT + PM_PLUS_30_NUM
#define PM_PLUS_40_OFT  PM_PLUS_35_OFT + PM_PLUS_35_NUM
#define PM_PLUS_45_OFT  PM_PLUS_40_OFT + PM_PLUS_40_NUM
#define PM_PLUS_50_OFT  PM_PLUS_45_OFT + PM_PLUS_45_NUM
#define PM_PLUS_55_OFT  PM_PLUS_50_OFT + PM_PLUS_50_NUM
#define PM_PLUS_60_OFT  PM_PLUS_55_OFT + PM_PLUS_55_NUM
#define PM_PLUS_65_OFT  PM_PLUS_60_OFT + PM_PLUS_60_NUM
#define PM_PLUS_70_OFT  PM_PLUS_65_OFT + PM_PLUS_65_NUM

#define PM_STAR_10_OFT  PM_PLUS_70_OFT + PM_PLUS_70_NUM
#define PM_STAR_15_OFT  PM_STAR_10_OFT + PM_STAR_10_NUM
#define PM_STAR_20_OFT  PM_STAR_15_OFT + PM_STAR_15_NUM
#define PM_STAR_25_OFT  PM_STAR_20_OFT + PM_STAR_20_NUM
#define PM_STAR_30_OFT  PM_STAR_25_OFT + PM_STAR_25_NUM
#define PM_STAR_35_OFT  PM_STAR_30_OFT + PM_STAR_30_NUM
#define PM_STAR_40_OFT  PM_STAR_35_OFT + PM_STAR_35_NUM
#define PM_STAR_45_OFT  PM_STAR_40_OFT + PM_STAR_40_NUM
#define PM_STAR_50_OFT  PM_STAR_45_OFT + PM_STAR_45_NUM
#define PM_STAR_55_OFT  PM_STAR_50_OFT + PM_STAR_50_NUM
#define PM_STAR_60_OFT  PM_STAR_55_OFT + PM_STAR_55_NUM
#define PM_STAR_65_OFT  PM_STAR_60_OFT + PM_STAR_60_NUM
#define PM_STAR_70_OFT  PM_STAR_65_OFT + PM_STAR_65_NUM

#define PM_CIRC_10_OFT  PM_STAR_70_OFT + PM_STAR_70_NUM
#define PM_CIRC_15_OFT  PM_CIRC_10_OFT + PM_CIRC_10_NUM
#define PM_CIRC_20_OFT  PM_CIRC_15_OFT + PM_CIRC_15_NUM
#define PM_CIRC_25_OFT  PM_CIRC_20_OFT + PM_CIRC_20_NUM
#define PM_CIRC_30_OFT  PM_CIRC_25_OFT + PM_CIRC_25_NUM
#define PM_CIRC_35_OFT  PM_CIRC_30_OFT + PM_CIRC_30_NUM
#define PM_CIRC_40_OFT  PM_CIRC_35_OFT + PM_CIRC_35_NUM
#define PM_CIRC_45_OFT  PM_CIRC_40_OFT + PM_CIRC_40_NUM
#define PM_CIRC_50_OFT  PM_CIRC_45_OFT + PM_CIRC_45_NUM
#define PM_CIRC_55_OFT  PM_CIRC_50_OFT + PM_CIRC_50_NUM
#define PM_CIRC_60_OFT  PM_CIRC_55_OFT + PM_CIRC_55_NUM
#define PM_CIRC_65_OFT  PM_CIRC_60_OFT + PM_CIRC_60_NUM
#define PM_CIRC_70_OFT  PM_CIRC_65_OFT + PM_CIRC_65_NUM

#define PM_CROSS_10_OFT  PM_CIRC_70_OFT + PM_CIRC_70_NUM
#define PM_CROSS_15_OFT  PM_CROSS_10_OFT + PM_CROSS_10_NUM
#define PM_CROSS_20_OFT  PM_CROSS_15_OFT + PM_CROSS_15_NUM
#define PM_CROSS_25_OFT  PM_CROSS_20_OFT + PM_CROSS_20_NUM
#define PM_CROSS_30_OFT  PM_CROSS_25_OFT + PM_CROSS_25_NUM
#define PM_CROSS_35_OFT  PM_CROSS_30_OFT + PM_CROSS_30_NUM
#define PM_CROSS_40_OFT  PM_CROSS_35_OFT + PM_CROSS_35_NUM
#define PM_CROSS_45_OFT  PM_CROSS_40_OFT + PM_CROSS_40_NUM
#define PM_CROSS_50_OFT  PM_CROSS_45_OFT + PM_CROSS_45_NUM
#define PM_CROSS_55_OFT  PM_CROSS_50_OFT + PM_CROSS_50_NUM
#define PM_CROSS_60_OFT  PM_CROSS_55_OFT + PM_CROSS_55_NUM
#define PM_CROSS_65_OFT  PM_CROSS_60_OFT + PM_CROSS_60_NUM
#define PM_CROSS_70_OFT  PM_CROSS_65_OFT + PM_CROSS_65_NUM

static const PM_FONT_INFO arrPMFontInfo[][TEL_NO_OF_SIZES] =
{
 // TOM_POINT - not used
 {{0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0},
  {0, 0, 0}},

 // TOM_PLUS
 {{ 9.f,  9.f, PM_PLUS_10_OFT},
  {11.f, 11.f, PM_PLUS_15_OFT},
  {13.f, 13.f, PM_PLUS_20_OFT},
  {15.f, 15.f, PM_PLUS_25_OFT},
  {17.f, 17.f, PM_PLUS_30_OFT},
  {19.f, 19.f, PM_PLUS_35_OFT},
  {21.f, 21.f, PM_PLUS_40_OFT},
  {23.f, 23.f, PM_PLUS_45_OFT},
  {25.f, 25.f, PM_PLUS_50_OFT},
  {27.f, 27.f, PM_PLUS_55_OFT},
  {29.f, 29.f, PM_PLUS_60_OFT},
  {31.f, 31.f, PM_PLUS_65_OFT},
  {32.f, 32.f, PM_PLUS_70_OFT}},

 // TOM_STAR
 {{ 7.f,  9.f, PM_STAR_10_OFT},
  {9.f,  11.f, PM_STAR_15_OFT},
  {11.f, 13.f, PM_STAR_20_OFT},
  {13.f, 15.f, PM_STAR_25_OFT},
  {13.f, 17.f, PM_STAR_30_OFT},
  {15.f, 19.f, PM_STAR_35_OFT},
  {17.f, 21.f, PM_STAR_40_OFT},
  {19.f, 23.f, PM_STAR_45_OFT},
  {21.f, 25.f, PM_STAR_50_OFT},
  {23.f, 27.f, PM_STAR_55_OFT},
  {25.f, 29.f, PM_STAR_60_OFT},
  {32.f, 32.f, PM_STAR_65_OFT},
  {32.f, 32.f, PM_STAR_70_OFT}},

 // TOM_X
 {{ 7.f,  7.f, PM_CROSS_10_OFT},
  { 9.f,  9.f, PM_CROSS_15_OFT},
  {11.f, 11.f, PM_CROSS_20_OFT},
  {13.f, 13.f, PM_CROSS_25_OFT},
  {15.f, 15.f, PM_CROSS_30_OFT},
  {17.f, 17.f, PM_CROSS_35_OFT},
  {19.f, 19.f, PM_CROSS_40_OFT},
  {21.f, 21.f, PM_CROSS_45_OFT},
  {23.f, 23.f, PM_CROSS_50_OFT},
  {25.f, 25.f, PM_CROSS_55_OFT},
  {27.f, 27.f, PM_CROSS_60_OFT},
  {32.f, 32.f, PM_CROSS_65_OFT},
  {32.f, 32.f, PM_CROSS_70_OFT}},

 // TOM_O
 {{ 7.f,  7.f, PM_CIRC_10_OFT},
  { 9.f,  9.f, PM_CIRC_15_OFT},
  { 9.f,  9.f, PM_CIRC_20_OFT},
  {11.f, 11.f, PM_CIRC_25_OFT},
  {13.f, 13.f, PM_CIRC_30_OFT},
  {15.f, 15.f, PM_CIRC_35_OFT},
  {17.f, 17.f, PM_CIRC_40_OFT},
  {19.f, 19.f, PM_CIRC_45_OFT},
  {21.f, 21.f, PM_CIRC_50_OFT},
  {23.f, 23.f, PM_CIRC_55_OFT},
  {25.f, 25.f, PM_CIRC_60_OFT},
  {27.f, 27.f, PM_CIRC_65_OFT},
  {29.f, 29.f, PM_CIRC_70_OFT}}
};

static const Standard_Byte OpenGl_AspectMarker_myMarkerRaster[] =
{
    // TYPE = PLUS

    0x08,0x00,
    0x08,0x00,
    0x08,0x00,
    0x08,0x00,
    0xff,0x80,
    0x08,0x00,
    0x08,0x00,
    0x08,0x00,
    0x08,0x00, // PLUS 9x9 = 1.0

    0x04,0x00,
    0x04,0x00,
    0x04,0x00,
    0x04,0x00,
    0x04,0x00,
    0xff,0xe0,
    0x04,0x00,
    0x04,0x00,
    0x04,0x00,
    0x04,0x00,
    0x04,0x00, // PLUS 11x11 = 1.5

    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0xff,0xf8,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00, // PLUS 13x13 = 2.0

    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0xff,0xfe,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00, // PLUS 15x15 = 2.5

    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0xff,0xff, 0x80,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00, // PLUS 17x17 = 3.0

    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0xff,0xff, 0xe0,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00, // PLUS 19x19 = 3.5

    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0xff,0xff, 0xf8,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00, // PLUS 21x21 = 4.0

    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0xff,0xff, 0xfe,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00, // PLUS 23x23 = 4.5

    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0xff,0xff, 0xff,0x80,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00, // PLUS 25x25 = 5.0

    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0xff,0xff, 0xff,0xe0,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x04, 0x00,0x00, // PLUS 27x27 = 5.5

    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0xff,0xff, 0xff,0xf8,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00,
    0x00,0x02, 0x00,0x00, // PLUS 29x29 = 6.0

    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0xff,0xff, 0xff,0xfd,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00,
    0x00,0x01, 0x00,0x00, // PLUS 31x31 = 6.5

    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0xff,0xff, 0xff,0xff,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00, // PLUS 32x32 = 7.0

    // TYPE = STAR

    0x10,
    0x10,
    0xd6,
    0x38,
    0x10,
    0x38,
    0xd6,
    0x10,
    0x10, // STAR 7x9 = 1.0

    0x08,0x00,
    0x08,0x00,
    0x08,0x00,
    0xc9,0x80,
    0x3e,0x00,
    0x08,0x00,
    0x3e,0x00,
    0xc9,0x80,
    0x08,0x00,
    0x08,0x00,
    0x08,0x00, // STAR 9x11 = 1.5

    0x04,0x00,
    0x04,0x00,
    0x04,0x00,
    0x84,0x20,
    0x64,0xc0,
    0x1f,0x00,
    0x04,0x00,
    0x1f,0x00,
    0x64,0xc0,
    0x84,0x20,
    0x04,0x00,
    0x04,0x00,
    0x04,0x00, // STAR 11x13 = 2.0

    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x82,0x18,
    0x62,0x60,
    0x1b,0x80,
    0x06,0x00,
    0x1b,0x80,
    0x62,0x60,
    0x82,0x18,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00, // STAR 13x15 = 2.5

    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x82,0x08,
    0x62,0x30,
    0x12,0x40,
    0x0f,0x80,
    0x02,0x00,
    0x0f,0x80,
    0x12,0x40,
    0x62,0x30,
    0x82,0x08,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00,
    0x02,0x00, // STAR 13x17 = 3.0

    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0xc1,0x06,
    0x21,0x18,
    0x19,0x20,
    0x07,0xc0,
    0x01,0x00,
    0x07,0xc0,
    0x19,0x20,
    0x21,0x18,
    0xc1,0x06,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00,
    0x01,0x00, // STAR 15x19 = 3.5

    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x80,0x80, 0x80,
    0x60,0x83, 0x00,
    0x10,0x8c, 0x00,
    0x0c,0x90, 0x00,
    0x03,0xe0, 0x00,
    0x00,0x80, 0x00,
    0x03,0xe0, 0x00,
    0x0c,0x90, 0x00,
    0x10,0x8c, 0x00,
    0x60,0x83, 0x00,
    0x80,0x80, 0x80,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00,
    0x00,0x80, 0x00, // STAR 17x21 = 4.0

    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0xc0,0x40, 0x60,
    0x30,0x41, 0x80,
    0x08,0x42, 0x00,
    0x06,0x4c, 0x00,
    0x01,0xf0, 0x00,
    0x00,0x40, 0x00,
    0x01,0xf0, 0x00,
    0x06,0x4c, 0x00,
    0x08,0x42, 0x00,
    0x30,0x41, 0x80,
    0xc0,0x40, 0x60,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00,
    0x00,0x40, 0x00, // STAR 19x23 = 4.5

    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x80,0x20, 0x08,
    0x60,0x20, 0x30,
    0x18,0x20, 0xc0,
    0x04,0x21, 0x00,
    0x03,0x26, 0x00,
    0x00,0xf8, 0x00,
    0x00,0x20, 0x00,
    0x00,0xf8, 0x00,
    0x03,0x26, 0x00,
    0x04,0x21, 0x00,
    0x18,0x20, 0xc0,
    0x60,0x20, 0x30,
    0x80,0x20, 0x08,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00,
    0x00,0x20, 0x00, // STAR 21x25 = 5.0

    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0xc0,0x10, 0x06,
    0x30,0x10, 0x18,
    0x08,0x10, 0x60,
    0x06,0x10, 0x80,
    0x01,0x93, 0x00,
    0x00,0x7c, 0x00,
    0x00,0x10, 0x00,
    0x00,0x7c, 0x00,
    0x01,0x93, 0x00,
    0x06,0x10, 0x80,
    0x08,0x10, 0x60,
    0x30,0x10, 0x18,
    0xc0,0x10, 0x06,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00,
    0x00,0x10, 0x00, // STAR 23x27 = 5.5

    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x80,0x08, 0x00,0x80,
    0x60,0x08, 0x03,0x00,
    0x18,0x08, 0x0c,0x00,
    0x04,0x08, 0x30,0x00,
    0x03,0x08, 0x40,0x00,
    0x00,0xc9, 0x80,0x00,
    0x00,0x3e, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x3e, 0x00,0x00,
    0x00,0xc9, 0x80,0x00,
    0x03,0x08, 0x40,0x00,
    0x04,0x08, 0x30,0x00,
    0x18,0x08, 0x0c,0x00,
    0x60,0x08, 0x03,0x00,
    0x80,0x08, 0x00,0x80,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x08, 0x00,0x00, // STAR 25x29 = 6.0

    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x30,0x00, 0x80,0x06,
    0x0c,0x00, 0x80,0x18,
    0x03,0x00, 0x80,0x60,
    0x00,0xc0, 0x81,0x80,
    0x00,0x30, 0x86,0x00,
    0x00,0x0c, 0x98,0x00,
    0x00,0x03, 0xe0,0x00,
    0x00,0x03, 0xe0,0x00,
    0x00,0x0c, 0x98,0x00,
    0x00,0x30, 0x86,0x00,
    0x00,0xc0, 0x81,0x80,
    0x03,0x00, 0x80,0x60,
    0x0c,0x00, 0x80,0x18,
    0x30,0x00, 0x80,0x06,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x80,0x00,
    0x00,0x00, 0x00,0x00,
    0x00,0x00, 0x00,0x00, // STAR 32x32 = 6.5

    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x10, 0x00, 0x80, 0x04,
    0x0c, 0x00, 0x80, 0x18,
    0x02, 0x00, 0x80, 0x20,
    0x01, 0x80, 0x80, 0xc0,
    0x00, 0x40, 0x81, 0x00,
    0x00, 0x30, 0x86, 0x00,
    0x00, 0x08, 0x88, 0x00,
    0x00, 0x06, 0xb0, 0x00,
    0x00, 0x01, 0xc0, 0x00,
    0x00, 0x06, 0xb0, 0x00,
    0x00, 0x08, 0x88, 0x00,
    0x00, 0x30, 0x86, 0x00,
    0x00, 0x40, 0x81, 0x00,
    0x01, 0x80, 0x80, 0xc0,
    0x02, 0x00, 0x80, 0x20,
    0x0c, 0x00, 0x80, 0x18,
    0x10, 0x00, 0x80, 0x04,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x80, 0x00, // STAR 32x32 = 7.0

    // TYPE = CIRC

    0x38,
    0x44,
    0x82,
    0x82,
    0x82,
    0x44,
    0x38, // CIRC 7x7 = 1.0

    0x3c,0x00,
    0x42,0x00,
    0x81,0x00,
    0x81,0x00,
    0x81,0x00,
    0x81,0x00,
    0x42,0x00,
    0x3c,0x00,
    0x00,0x00, //CIRC 9x9 = 1.5

    0x3e,0x00,
    0x41,0x00,
    0x81,0x80,
    0x80,0x80,
    0x80,0x80,
    0x80,0x80,
    0x81,0x80,
    0x41,0x00,
    0x3e,0x00, // CIRC 9x9 = 2.0

    0x1f,0x00,
    0x20,0x80,
    0x40,0x40,
    0x80,0x20,
    0x80,0x20,
    0x80,0x20,
    0x80,0x20,
    0x80,0x20,
    0x40,0x40,
    0x20,0x80,
    0x1f,0x00, // CIRC 11x11 = 2.5

    0x0f,0x80,
    0x10,0x40,
    0x20,0x20,
    0x40,0x10,
    0x80,0x08,
    0x80,0x08,
    0x80,0x08,
    0x80,0x08,
    0x80,0x08,
    0x40,0x10,
    0x20,0x20,
    0x10,0x40,
    0x0f,0x80, // CIRC 13x13 = 3.0

    0x07,0xc0,
    0x18,0x30,
    0x20,0x08,
    0x40,0x04,
    0x40,0x04,
    0x80,0x02,
    0x80,0x02,
    0x80,0x02,
    0x80,0x02,
    0x80,0x02,
    0x40,0x04,
    0x40,0x04,
    0x20,0x08,
    0x18,0x30,
    0x07,0xc0, // CIRC 15x15 = 3.5

    0x03,0xe0, 0x00,
    0x0c,0x18, 0x00,
    0x10,0x04, 0x00,
    0x20,0x02, 0x00,
    0x40,0x01, 0x00,
    0x40,0x01, 0x00,
    0x80,0x00, 0x80,
    0x80,0x00, 0x80,
    0x80,0x00, 0x80,
    0x80,0x00, 0x80,
    0x80,0x00, 0x80,
    0x40,0x01, 0x00,
    0x40,0x01, 0x00,
    0x20,0x02, 0x00,
    0x10,0x04, 0x00,
    0x0c,0x18, 0x00,
    0x03,0xe0, 0x00, // CIRC 17x17 = 4.0

    0x03,0xf8, 0x00,
    0x0e,0x0e, 0x00,
    0x18,0x03, 0x00,
    0x20,0x00, 0x80,
    0x60,0x00, 0xc0,
    0x40,0x00, 0x40,
    0xc0,0x00, 0x60,
    0x80,0x00, 0x20,
    0x80,0x00, 0x20,
    0x80,0x00, 0x20,
    0x80,0x00, 0x20,
    0x80,0x00, 0x20,
    0xc0,0x00, 0x60,
    0x40,0x00, 0x40,
    0x60,0x00, 0xc0,
    0x20,0x00, 0x80,
    0x18,0x03, 0x00,
    0x0e,0x0e, 0x00,
    0x03,0xf8, 0x00, // CIRC 19x19 = 4.5

    0x01,0xfc, 0x00,
    0x06,0x03, 0x00,
    0x08,0x00, 0x80,
    0x10,0x00, 0x40,
    0x20,0x00, 0x20,
    0x40,0x00, 0x10,
    0x40,0x00, 0x10,
    0x80,0x00, 0x08,
    0x80,0x00, 0x08,
    0x80,0x00, 0x08,
    0x80,0x00, 0x08,
    0x80,0x00, 0x08,
    0x80,0x00, 0x08,
    0x80,0x00, 0x08,
    0x40,0x00, 0x10,
    0x40,0x00, 0x10,
    0x20,0x00, 0x20,
    0x10,0x00, 0x40,
    0x08,0x00, 0x80,
    0x06,0x03, 0x00,
    0x01,0xfc, 0x00, // CIRC 21x21 = 5.0

    0x00,0xfe, 0x00,
    0x03,0x01, 0x80,
    0x0c,0x00, 0x60,
    0x18,0x00, 0x30,
    0x30,0x00, 0x18,
    0x20,0x00, 0x08,
    0x40,0x00, 0x04,
    0x40,0x00, 0x04,
    0x80,0x00, 0x02,
    0x80,0x00, 0x02,
    0x80,0x00, 0x02,
    0x80,0x00, 0x02,
    0x80,0x00, 0x02,
    0x80,0x00, 0x02,
    0x80,0x00, 0x02,
    0x40,0x00, 0x04,
    0x40,0x00, 0x04,
    0x20,0x00, 0x08,
    0x30,0x00, 0x18,
    0x18,0x00, 0x30,
    0x0c,0x00, 0x60,
    0x03,0x01, 0x80,
    0x00,0xfe, 0x00, // CIRC 23x23 = 5.5

    0x00,0x7f, 0x00,0x00,
    0x01,0x80, 0xc0,0x00,
    0x06,0x00, 0x30,0x00,
    0x08,0x00, 0x08,0x00,
    0x10,0x00, 0x04,0x00,
    0x20,0x00, 0x02,0x00,
    0x20,0x00, 0x02,0x00,
    0x40,0x00, 0x01,0x00,
    0x40,0x00, 0x01,0x00,
    0x80,0x00, 0x00,0x80,
    0x80,0x00, 0x00,0x80,
    0x80,0x00, 0x00,0x80,
    0x80,0x00, 0x00,0x80,
    0x80,0x00, 0x00,0x80,
    0x80,0x00, 0x00,0x80,
    0x80,0x00, 0x00,0x80,
    0x40,0x00, 0x01,0x00,
    0x40,0x00, 0x01,0x00,
    0x20,0x00, 0x02,0x00,
    0x20,0x00, 0x02,0x00,
    0x10,0x00, 0x04,0x00,
    0x08,0x00, 0x08,0x00,
    0x06,0x00, 0x30,0x00,
    0x01,0x80, 0xc0,0x00,
    0x00,0x7f, 0x00,0x00, // CIRC 25x25 = 6.0

    0x00,0x3f, 0x80,0x00,
    0x01,0xc0, 0x70,0x00,
    0x03,0x00, 0x18,0x00,
    0x0c,0x00, 0x06,0x00,
    0x18,0x00, 0x03,0x00,
    0x10,0x00, 0x01,0x00,
    0x20,0x00, 0x00,0x80,
    0x60,0x00, 0x00,0xc0,
    0x40,0x00, 0x00,0x40,
    0x40,0x00, 0x00,0x40,
    0x80,0x00, 0x00,0x20,
    0x80,0x00, 0x00,0x20,
    0x80,0x00, 0x00,0x20,
    0x80,0x00, 0x00,0x20,
    0x80,0x00, 0x00,0x20,
    0x80,0x00, 0x00,0x20,
    0x80,0x00, 0x00,0x20,
    0x40,0x00, 0x00,0x40,
    0x40,0x00, 0x00,0x40,
    0x60,0x00, 0x00,0xc0,
    0x20,0x00, 0x00,0x80,
    0x10,0x00, 0x01,0x00,
    0x18,0x00, 0x03,0x00,
    0x0c,0x00, 0x06,0x00,
    0x03,0x00, 0x18,0x00,
    0x01,0xc0, 0x70,0x00,
    0x00,0x3f, 0x80,0x00, // CIRC 27x27 = 6.5

    0x00,0x1f, 0xc0,0x00,
    0x00,0xe0, 0x38,0x00,
    0x01,0x00, 0x04,0x00,
    0x06,0x00, 0x03,0x00,
    0x08,0x00, 0x00,0x80,
    0x10,0x00, 0x00,0x40,
    0x10,0x00, 0x00,0x40,
    0x20,0x00, 0x00,0x20,
    0x40,0x00, 0x00,0x10,
    0x40,0x00, 0x00,0x10,
    0x40,0x00, 0x00,0x10,
    0x80,0x00, 0x00,0x08,
    0x80,0x00, 0x00,0x08,
    0x80,0x00, 0x00,0x08,
    0x80,0x00, 0x00,0x08,
    0x80,0x00, 0x00,0x08,
    0x80,0x00, 0x00,0x08,
    0x80,0x00, 0x00,0x08,
    0x40,0x00, 0x00,0x10,
    0x40,0x00, 0x00,0x10,
    0x40,0x00, 0x00,0x10,
    0x20,0x00, 0x00,0x20,
    0x10,0x00, 0x00,0x40,
    0x10,0x00, 0x00,0x40,
    0x08,0x00, 0x00,0x80,
    0x06,0x00, 0x03,0x00,
    0x01,0x00, 0x04,0x00,
    0x00,0xe0, 0x38,0x00,
    0x00,0x1f, 0xc0,0x00, // CIRC 29x29 = 7.0

    // TYPE = CROSS

    0x82,
    0x44,
    0x28,
    0x10,
    0x28,
    0x44,
    0x82, // CROSS 7x7 = 1.0

    0x80,0x80,
    0x41,0x00,
    0x22,0x00,
    0x14,0x00,
    0x08,0x00,
    0x14,0x00,
    0x22,0x00,
    0x41,0x00,
    0x80,0x80, // CROSS 9x9 = 1.5

    0x80,0x20,
    0x40,0x40,
    0x20,0x80,
    0x11,0x00,
    0x0a,0x00,
    0x04,0x00,
    0x0a,0x00,
    0x11,0x00,
    0x20,0x80,
    0x40,0x40,
    0x80,0x20, // CROSS 11x11 = 2.0

    0x80,0x08,
    0x40,0x10,
    0x20,0x20,
    0x10,0x40,
    0x08,0x80,
    0x05,0x00,
    0x02,0x00,
    0x05,0x00,
    0x08,0x80,
    0x10,0x40,
    0x20,0x20,
    0x40,0x10,
    0x80,0x08, // CROSS 13x13 = 2.5

    0x80,0x02,
    0x40,0x04,
    0x20,0x08,
    0x10,0x10,
    0x08,0x20,
    0x04,0x40,
    0x02,0x80,
    0x01,0x00,
    0x02,0x80,
    0x04,0x40,
    0x08,0x20,
    0x10,0x10,
    0x20,0x08,
    0x40,0x04,
    0x80,0x02, // CROSS 15x15 = 3.0

    0x80,0x00, 0x80,
    0x40,0x01, 0x00,
    0x20,0x02, 0x00,
    0x10,0x04, 0x00,
    0x08,0x08, 0x00,
    0x04,0x10, 0x00,
    0x02,0x20, 0x00,
    0x01,0x40, 0x00,
    0x00,0x80, 0x00,
    0x01,0x40, 0x00,
    0x02,0x20, 0x00,
    0x04,0x10, 0x00,
    0x08,0x08, 0x00,
    0x10,0x04, 0x00,
    0x20,0x02, 0x00,
    0x40,0x01, 0x00,
    0x80,0x00, 0x80, // CROSS 17x17 = 3.5

    0x80,0x00, 0x20,
    0x40,0x00, 0x40,
    0x20,0x00, 0x80,
    0x10,0x01, 0x00,
    0x08,0x02, 0x00,
    0x04,0x04, 0x00,
    0x02,0x08, 0x00,
    0x01,0x10, 0x00,
    0x00,0xa0, 0x00,
    0x00,0x40, 0x00,
    0x00,0xa0, 0x00,
    0x01,0x10, 0x00,
    0x02,0x08, 0x00,
    0x04,0x04, 0x00,
    0x08,0x02, 0x00,
    0x10,0x01, 0x00,
    0x20,0x00, 0x80,
    0x40,0x00, 0x40,
    0x80,0x00, 0x20, // CROSS 19x19 = 4.0

    0x80,0x00, 0x08,
    0x40,0x00, 0x10,
    0x20,0x00, 0x20,
    0x10,0x00, 0x40,
    0x08,0x00, 0x80,
    0x04,0x01, 0x00,
    0x02,0x02, 0x00,
    0x01,0x04, 0x00,
    0x00,0x88, 0x00,
    0x00,0x50, 0x00,
    0x00,0x20, 0x00,
    0x00,0x50, 0x00,
    0x00,0x88, 0x00,
    0x01,0x04, 0x00,
    0x02,0x02, 0x00,
    0x04,0x01, 0x00,
    0x08,0x00, 0x80,
    0x10,0x00, 0x40,
    0x20,0x00, 0x20,
    0x40,0x00, 0x10,
    0x80,0x00, 0x08,/* CROSS 21x21 = 4.5 */

    0x80,0x00, 0x02,
    0x40,0x00, 0x04,
    0x20,0x00, 0x08,
    0x10,0x00, 0x10,
    0x08,0x00, 0x20,
    0x04,0x00, 0x40,
    0x02,0x00, 0x80,
    0x01,0x01, 0x00,
    0x00,0x82, 0x00,
    0x00,0x44, 0x00,
    0x00,0x28, 0x00,
    0x00,0x10, 0x00,
    0x00,0x28, 0x00,
    0x00,0x44, 0x00,
    0x00,0x82, 0x00,
    0x01,0x01, 0x00,
    0x02,0x00, 0x80,
    0x04,0x00, 0x40,
    0x08,0x00, 0x20,
    0x10,0x00, 0x10,
    0x20,0x00, 0x08,
    0x40,0x00, 0x04,
    0x80,0x00, 0x02, // CROSS 23x23 = 5.0

    0x80,0x00, 0x00,0x80,
    0x40,0x00, 0x01,0x00,
    0x20,0x00, 0x02,0x00,
    0x10,0x00, 0x04,0x00,
    0x08,0x00, 0x08,0x00,
    0x04,0x00, 0x10,0x00,
    0x02,0x00, 0x20,0x00,
    0x01,0x00, 0x40,0x00,
    0x00,0x80, 0x80,0x00,
    0x00,0x41, 0x00,0x00,
    0x00,0x22, 0x00,0x00,
    0x00,0x14, 0x00,0x00,
    0x00,0x08, 0x00,0x00,
    0x00,0x14, 0x00,0x00,
    0x00,0x22, 0x00,0x00,
    0x00,0x41, 0x00,0x00,
    0x00,0x80, 0x80,0x00,
    0x01,0x00, 0x40,0x00,
    0x02,0x00, 0x20,0x00,
    0x04,0x00, 0x10,0x00,
    0x08,0x00, 0x08,0x00,
    0x10,0x00, 0x04,0x00,
    0x20,0x00, 0x02,0x00,
    0x40,0x00, 0x01,0x00,
    0x80,0x00, 0x00,0x80, // CROSS 25x25 = 5.5

    0x80,0x00, 0x00,0x20,
    0x40,0x00, 0x00,0x40,
    0x20,0x00, 0x00,0x80,
    0x10,0x00, 0x01,0x00,
    0x08,0x00, 0x02,0x00,
    0x04,0x00, 0x04,0x00,
    0x02,0x00, 0x08,0x00,
    0x01,0x00, 0x10,0x00,
    0x00,0x80, 0x20,0x00,
    0x00,0x40, 0x40,0x00,
    0x00,0x20, 0x80,0x00,
    0x00,0x11, 0x00,0x00,
    0x00,0x0a, 0x00,0x00,
    0x00,0x04, 0x00,0x00,
    0x00,0x0a, 0x00,0x00,
    0x00,0x11, 0x00,0x00,
    0x00,0x20, 0x80,0x00,
    0x00,0x40, 0x40,0x00,
    0x00,0x80, 0x20,0x00,
    0x01,0x00, 0x10,0x00,
    0x02,0x00, 0x08,0x00,
    0x04,0x00, 0x04,0x00,
    0x08,0x00, 0x02,0x00,
    0x10,0x00, 0x01,0x00,
    0x20,0x00, 0x00,0x80,
    0x40,0x00, 0x00,0x40,
    0x80,0x00, 0x00,0x20, // CROSS 27x27 = 6.0

    0x00,0x00, 0x00,0x00,
    0x00,0x00, 0x00,0x00,
    0x20,0x00, 0x00,0x04,
    0x10,0x00, 0x00,0x08,
    0x08,0x00, 0x00,0x10,
    0x04,0x00, 0x00,0x20,
    0x02,0x00, 0x00,0x40,
    0x01,0x00, 0x00,0x80,
    0x00,0x80, 0x01,0x00,
    0x00,0x40, 0x02,0x00,
    0x00,0x20, 0x04,0x00,
    0x00,0x10, 0x08,0x00,
    0x00,0x08, 0x10,0x00,
    0x00,0x04, 0x20,0x00,
    0x00,0x02, 0x40,0x00,
    0x00,0x01, 0x80,0x00,
    0x00,0x01, 0x80,0x00,
    0x00,0x02, 0x40,0x00,
    0x00,0x04, 0x20,0x00,
    0x00,0x08, 0x10,0x00,
    0x00,0x10, 0x08,0x00,
    0x00,0x20, 0x04,0x00,
    0x00,0x40, 0x02,0x00,
    0x00,0x80, 0x01,0x00,
    0x01,0x00, 0x00,0x80,
    0x02,0x00, 0x00,0x40,
    0x04,0x00, 0x00,0x20,
    0x08,0x00, 0x00,0x10,
    0x10,0x00, 0x00,0x08,
    0x20,0x00, 0x00,0x04,
    0x00,0x00, 0x00,0x00,
    0x00,0x00, 0x00,0x00, // CROSS 32x32 = 6.5

    0x00,0x00, 0x00,0x00,
    0x40,0x00, 0x00,0x02,
    0x20,0x00, 0x00,0x04,
    0x10,0x00, 0x00,0x08,
    0x08,0x00, 0x00,0x10,
    0x04,0x00, 0x00,0x20,
    0x02,0x00, 0x00,0x40,
    0x01,0x00, 0x00,0x80,
    0x00,0x80, 0x01,0x00,
    0x00,0x40, 0x02,0x00,
    0x00,0x20, 0x04,0x00,
    0x00,0x10, 0x08,0x00,
    0x00,0x08, 0x10,0x00,
    0x00,0x04, 0x20,0x00,
    0x00,0x02, 0x40,0x00,
    0x00,0x01, 0x80,0x00,
    0x00,0x01, 0x80,0x00,
    0x00,0x02, 0x40,0x00,
    0x00,0x04, 0x20,0x00,
    0x00,0x08, 0x10,0x00,
    0x00,0x10, 0x08,0x00,
    0x00,0x20, 0x04,0x00,
    0x00,0x40, 0x02,0x00,
    0x00,0x80, 0x01,0x00,
    0x01,0x00, 0x00,0x80,
    0x02,0x00, 0x00,0x40,
    0x04,0x00, 0x00,0x20,
    0x08,0x00, 0x00,0x10,
    0x10,0x00, 0x00,0x08,
    0x20,0x00, 0x00,0x04,
    0x40,0x00, 0x00,0x02,
    0x00,0x00, 0x00,0x00  // CROSS 32x32 = 7.0
};

//! Returns a parameters for the marker of the specified type and scale.
static void GetMarkerBitMapParam (const Aspect_TypeOfMarker theMarkerType,
                                  const Standard_ShortReal& theScale,
                                  Standard_Integer& theWidth,
                                  Standard_Integer& theHeight,
                                  Standard_Integer& theOffset,
                                  Standard_Integer& theNumOfBytes)
{
  const Standard_Integer aType = (Standard_Integer )((theMarkerType > Aspect_TOM_O) ? Aspect_TOM_O : theMarkerType);
  const Standard_Real anIndex = (Standard_Real )(TEL_NO_OF_SIZES - 1) * (theScale - (Standard_Real )TEL_PM_START_SIZE)
                              / (Standard_Real )(TEL_PM_END_SIZE - TEL_PM_START_SIZE);
  Standard_Integer anId = (Standard_Integer )(anIndex + 0.5);
  if (anId < 0)
  {
    anId = 0;
  }
  else if (anId >= TEL_NO_OF_SIZES)
  {
    anId = TEL_NO_OF_SIZES - 1;
  }

  theWidth  = (Standard_Integer )arrPMFontInfo[aType][anId].width;
  theHeight = (Standard_Integer )arrPMFontInfo[aType][anId].height;
  theOffset = arrPMFontInfo[aType][anId].offset;
  const Standard_Integer aNumOfBytesInRow = theWidth / 8 + (theWidth % 8 ? 1 : 0);
  theNumOfBytes = theHeight * aNumOfBytesInRow;
}

//! Returns a marker image for the marker of the specified type and scale.
static Handle(Graphic3d_MarkerImage) GetTextureImage (const Aspect_TypeOfMarker theMarkerType,
                                                      const Standard_ShortReal& theScale)
{
  Standard_Integer aWidth, aHeight, anOffset, aNumOfBytes;
  GetMarkerBitMapParam (theMarkerType, theScale, aWidth, aHeight, anOffset, aNumOfBytes);

  Handle(TColStd_HArray1OfByte) aBitMap = new TColStd_HArray1OfByte (0, aNumOfBytes - 1);
  for (Standard_Integer anIter = 0; anIter < aNumOfBytes; anIter++)
  {
    aBitMap->ChangeValue (anIter) = OpenGl_AspectMarker_myMarkerRaster[anOffset + anIter];
  }

  Handle(Graphic3d_MarkerImage) aTexture = new Graphic3d_MarkerImage (aBitMap, aWidth, aHeight);
  return aTexture;
}

//! Merge two image pixmap into one. Used for creating image for following markers:
//! Aspect_TOM_O_POINT, Aspect_TOM_O_PLUS, Aspect_TOM_O_STAR, Aspect_TOM_O_X, Aspect_TOM_RING1, Aspect_TOM_RING2, Aspect_TOM_RING3
static Handle(Image_PixMap) MergeImages (const Handle(Image_PixMap)& theImage1,
                                         const Handle(Image_PixMap)& theImage2)
{
  if (theImage1.IsNull() && theImage2.IsNull())
  {
    return Handle(Image_PixMap)();
  }

  Handle(Image_PixMap) aResultImage = new Image_PixMap();

  Standard_Integer aWidth1 (0), aHeight1 (0);
  if (!theImage1.IsNull())
  {
    aWidth1  = (Standard_Integer )theImage1->Width();
    aHeight1 = (Standard_Integer )theImage1->Height();
  }

  Standard_Integer aWidth2 (0), aHeight2 (0);
  if (!theImage2.IsNull())
  {
    aWidth2  = (Standard_Integer )theImage2->Width();
    aHeight2 = (Standard_Integer )theImage2->Height();
  }

  const Standard_Integer aMaxWidth  = Max (aWidth1,   aWidth2);
  const Standard_Integer aMaxHeight = Max (aHeight1,  aHeight2);
  const Standard_Integer aSize      = Max (aMaxWidth, aMaxHeight);

  aResultImage->InitZero (Image_Format_Alpha, aSize, aSize);

  if (!theImage1.IsNull())
  {
    const Standard_Integer aXOffset1  = Abs (aWidth1  - aMaxWidth)  / 2;
    const Standard_Integer anYOffset1 = Abs (aHeight1 - aMaxHeight) / 2;
    for (Standard_Integer anY = 0; anY < aHeight1; anY++)
    {
      Standard_Byte* anImageLine = theImage1->ChangeRow (anY);
      Standard_Byte* aResultImageLine = aResultImage->ChangeRow (anYOffset1 + anY);
      for (Standard_Integer aX = 0; aX < aWidth1; aX++)
      {
        aResultImageLine[aXOffset1 + aX] |= anImageLine[aX];
      }
    }
  }

  if (!theImage2.IsNull())
  {
    const Standard_Integer aXOffset2  = Abs (aWidth2  - aMaxWidth)  / 2;
    const Standard_Integer anYOffset2 = Abs (aHeight2 - aMaxHeight) / 2;
    for (Standard_Integer anY = 0; anY < aHeight2; anY++)
    {
      Standard_Byte* anImageLine = theImage2->ChangeRow (anY);
      Standard_Byte* aResultImageLine = aResultImage->ChangeRow (anYOffset2 + anY);
      for (Standard_Integer aX = 0; aX < aWidth2; aX++)
      {
        aResultImageLine[aXOffset2 + aX] |= anImageLine[aX];
      }
    }
  }

  return aResultImage;
}

// =======================================================================
// function : Release
// purpose  :
// =======================================================================
void OpenGl_AspectsSprite::Release (OpenGl_Context* theCtx)
{
  myIsSpriteReady = Standard_False;
  if (mySprite.IsNull())
  {
    return;
  }

  if (theCtx != NULL)
  {
    if (mySprite->ResourceId().IsEmpty())
    {
      theCtx->DelayedRelease (mySprite);
      theCtx->DelayedRelease (mySpriteA);
    }
    else
    {
      {
        const TCollection_AsciiString aSpriteKey = mySprite->ResourceId();
        mySprite.Nullify(); // we need nullify all handles before ReleaseResource() call
        theCtx->ReleaseResource (aSpriteKey,  Standard_True);
      }
      if (!mySpriteA.IsNull())
      {
        const TCollection_AsciiString aSpriteKeyA = mySpriteA->ResourceId();
        mySpriteA.Nullify();
        theCtx->ReleaseResource (aSpriteKeyA, Standard_True);
      }
    }
  }
  mySprite.Nullify();
  mySpriteA.Nullify();
}

// =======================================================================
// function : HasPointSprite
// purpose  :
// =======================================================================
bool OpenGl_AspectsSprite::HasPointSprite (const Handle(OpenGl_Context)& theCtx,
                                           const Handle(Graphic3d_Aspects)& theAspects)
{
  const Handle(OpenGl_PointSprite)& aSprite = Sprite (theCtx, theAspects, false);
  return !aSprite.IsNull()
      && !aSprite->IsDisplayList();
}

// =======================================================================
// function : IsDisplayListSprite
// purpose  :
// =======================================================================
bool OpenGl_AspectsSprite::IsDisplayListSprite (const Handle(OpenGl_Context)& theCtx,
                                                const Handle(Graphic3d_Aspects)& theAspects)
{
#if !defined(GL_ES_VERSION_2_0)
  const Handle(OpenGl_PointSprite)& aSprite = Sprite (theCtx, theAspects, false);
  return !aSprite.IsNull()
       && aSprite->IsDisplayList();
#else
  (void )theCtx;
  (void )theAspects;
  return false;
#endif
}

// =======================================================================
// function : UpdateRediness
// purpose  :
// =======================================================================
void OpenGl_AspectsSprite::UpdateRediness (const Handle(Graphic3d_Aspects)& theAspect)
{
  // update sprite resource bindings
  TCollection_AsciiString aSpriteKeyNew, aSpriteAKeyNew;
  spriteKeys (theAspect->MarkerImage(), theAspect->MarkerType(), theAspect->MarkerScale(), theAspect->ColorRGBA(), aSpriteKeyNew, aSpriteAKeyNew);
  const TCollection_AsciiString& aSpriteKeyOld  = !mySprite.IsNull()  ? mySprite ->ResourceId() : THE_EMPTY_KEY;
  const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY;
  if (aSpriteKeyNew.IsEmpty()  || aSpriteKeyOld  != aSpriteKeyNew
   || aSpriteAKeyNew.IsEmpty() || aSpriteAKeyOld != aSpriteAKeyNew)
  {
    myIsSpriteReady = Standard_False;
    myMarkerSize = theAspect->MarkerScale();
  }
}

// =======================================================================
// function : Sprite
// purpose  :
// =======================================================================
const Handle(OpenGl_PointSprite)& OpenGl_AspectsSprite::Sprite (const Handle(OpenGl_Context)& theCtx,
                                                                const Handle(Graphic3d_Aspects)& theAspects,
                                                                bool theIsAlphaSprite)
{
  if (!myIsSpriteReady)
  {
    build (theCtx, theAspects->MarkerImage(), theAspects->MarkerType(), theAspects->MarkerScale(), theAspects->ColorRGBA(), myMarkerSize);
    myIsSpriteReady = true;
  }
  return theIsAlphaSprite && !mySpriteA.IsNull() && mySpriteA->IsValid()
       ? mySpriteA
       : mySprite;
}

// =======================================================================
// function : build
// purpose  :
// =======================================================================
void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
                                  const Handle(Graphic3d_MarkerImage)& theMarkerImage,
                                  Aspect_TypeOfMarker theType,
                                  Standard_ShortReal theScale,
                                  const Graphic3d_Vec4& theColor,
                                  Standard_ShortReal& theMarkerSize)
{
  // generate key for shared resource
  TCollection_AsciiString aNewKey, aNewKeyA;
  spriteKeys (theMarkerImage, theType, theScale, theColor, aNewKey, aNewKeyA);

  const TCollection_AsciiString& aSpriteKeyOld  = !mySprite.IsNull()  ? mySprite ->ResourceId() : THE_EMPTY_KEY;
  const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY;

  // release old shared resources
  const Standard_Boolean aNewResource = aNewKey.IsEmpty()
                                     || aSpriteKeyOld != aNewKey;
  if (aNewResource)
  {
    if (!mySprite.IsNull())
    {
      if (mySprite->ResourceId().IsEmpty())
      {
        theCtx->DelayedRelease (mySprite);
        mySprite.Nullify();
      }
      else
      {
        const TCollection_AsciiString anOldKey = mySprite->ResourceId();
        mySprite.Nullify(); // we need nullify all handles before ReleaseResource() call
        theCtx->ReleaseResource (anOldKey, Standard_True);
      }
    }
  }
  if (aNewKeyA.IsEmpty() || aSpriteAKeyOld != aNewKeyA)
  {
    if (!mySpriteA.IsNull())
    {
      if (mySpriteA->ResourceId().IsEmpty())
      {
        theCtx->DelayedRelease (mySpriteA);
        mySpriteA.Nullify();
      }
      else
      {
        const TCollection_AsciiString anOldKey = mySpriteA->ResourceId();
        mySpriteA.Nullify(); // we need nullify all handles before ReleaseResource() call
        theCtx->ReleaseResource (anOldKey, Standard_True);
      }
    }
  }

  if (!aNewResource)
  {
    const OpenGl_PointSprite* aSprite = dynamic_cast<OpenGl_PointSprite*> (mySprite.get());
    if (!aSprite->IsDisplayList())
    {
      theMarkerSize = Standard_ShortReal (Max (aSprite->SizeX(), aSprite->SizeY()));
    }
    return;
  }
  if (theType == Aspect_TOM_POINT
   || theType == Aspect_TOM_EMPTY
   || (theType == Aspect_TOM_USERDEFINED && theMarkerImage.IsNull()))
  {
    // nothing to do - just simple point
    return;
  }

  Handle(OpenGl_PointSprite)& aSprite  = mySprite;
  Handle(OpenGl_PointSprite)& aSpriteA = mySpriteA;
  if (!aNewKey.IsEmpty()
   && theCtx->GetResource<Handle(OpenGl_PointSprite)> (aNewKeyA, aSpriteA) // alpha sprite could be shared
   && theCtx->GetResource<Handle(OpenGl_PointSprite)> (aNewKey,  aSprite))
  {
    // reuse shared resource
    if (!aSprite->IsDisplayList())
    {
      theMarkerSize = Standard_ShortReal (Max (aSprite->SizeX(), aSprite->SizeY()));
    }
    return;
  }

  const bool hadAlreadyAlpha = !aSpriteA.IsNull();
  if (!hadAlreadyAlpha)
  {
    aSpriteA = new OpenGl_PointSprite (aNewKeyA);
  }
  aSprite = new OpenGl_PointSprite (aNewKey);
  if (!aNewKey.IsEmpty())
  {
    theCtx->ShareResource (aNewKey, aSprite);
    if (!hadAlreadyAlpha)
    {
      theCtx->ShareResource (aNewKeyA, aSpriteA);
    }
  }

  if (!theCtx.IsNull()
   &&  theCtx->core20fwd != NULL
   && !theCtx->caps->pntSpritesDisable)
  {
    // Creating texture resource for using it with point sprites
    Handle(Graphic3d_MarkerImage) aNewMarkerImage;
    Handle(Image_PixMap) anImage, anImageA;

    if (theType == Aspect_TOM_USERDEFINED && !theMarkerImage.IsNull())
    {
      aNewMarkerImage = theMarkerImage;
      anImage = aNewMarkerImage->GetImage();
    }
    else
    {
      // Creating image from default bitmap
      Handle(Graphic3d_MarkerImage) aMarkerImage1, aMarkerImage2;

      const Standard_ShortReal aDelta = 0.1F;
      Standard_ShortReal aScale = theScale;
      Standard_ShortReal aLimit = 0.0F;

      switch (theType)
      {
        case Aspect_TOM_O_POINT:
        {
          // draw inner point as filled rectangle
          const Standard_Integer        aSize   = theScale > 7 ? 7 : (Standard_Integer )(theScale + 0.5F);
          Handle(TColStd_HArray1OfByte) aBitMap = fillPointBitmap (aSize);
          aMarkerImage2 = new Graphic3d_MarkerImage (aBitMap, aSize, aSize);
        }
        Standard_FALLTHROUGH
        case Aspect_TOM_O_PLUS:
        case Aspect_TOM_O_STAR:
        case Aspect_TOM_O_X:
        {
          // For this type of markers we merge two base bitmaps into one
          // For example Aspect_TOM_O_PLUS = Aspect_TOM_O + Aspect_TOM_PLUS
          aMarkerImage1 = GetTextureImage (Aspect_TOM_O, theScale);
          if (theType != Aspect_TOM_O_POINT)
          {
            aMarkerImage2 = GetTextureImage (Aspect_TypeOfMarker (theType - Aspect_TOM_O_POINT), theScale);
          }
          anImage = MergeImages (aMarkerImage1->GetImage(), aMarkerImage2->GetImage());
          aNewMarkerImage = new Graphic3d_MarkerImage (anImage);
          break;
        }
        case Aspect_TOM_RING1:
          if (aLimit == 0.0f) aLimit = aScale * 0.2f;
          Standard_FALLTHROUGH
        case Aspect_TOM_RING2:
          if (aLimit == 0.0f) aLimit = aScale * 0.5f;
          Standard_FALLTHROUGH
        case Aspect_TOM_RING3:
        {
          if (aLimit == 0.0f) aLimit = aScale * 0.8f;
          for (; aScale > aLimit && aScale >= 1.0f; aScale -= aDelta)
          {
            anImage = MergeImages (anImage, GetTextureImage (Aspect_TOM_O, aScale)->GetImage());
          }
          aNewMarkerImage = new Graphic3d_MarkerImage (anImage);
          break;
        }
        case Aspect_TOM_BALL:
        {
          Standard_Integer aWidth, aHeight, anOffset, aNumOfBytes;
          GetMarkerBitMapParam (Aspect_TOM_O, aScale, aWidth, aHeight, anOffset, aNumOfBytes);

          NCollection_Vec4<Standard_Real> aColor (Standard_Real (theColor.r()),
                                                  Standard_Real (theColor.g()),
                                                  Standard_Real (theColor.b()),
                                                  Standard_Real (theColor.a()));

          const Standard_Integer aSize = Max (aWidth + 2, aHeight + 2); // includes extra margin
          anImage  = new Image_PixMap();
          anImageA = new Image_PixMap();
          anImage ->InitZero (Image_Format_BGRA,  aSize, aSize);
          anImageA->InitZero (Image_Format_Alpha, aSize, aSize);

          // we draw a set of circles
          Image_ColorBGRA aColor32;
          aColor32.a() = 255;
          Standard_Real aHLS[3];
          while (aScale >= 1.0f)
          {
            Quantity_Color::RgbHls (aColor.r(), aColor.g(), aColor.b(), aHLS[0], aHLS[1], aHLS[2]);
            aHLS[2] *= 0.95; // 5% saturation change
            Quantity_Color::HlsRgb (aHLS[0], aHLS[1], aHLS[2], aColor.r(), aColor.g(), aColor.b());
            aColor32.r() = Standard_Byte(255.0 * aColor.r());
            aColor32.g() = Standard_Byte(255.0 * aColor.g());
            aColor32.b() = Standard_Byte(255.0 * aColor.b());

            const Handle(Graphic3d_MarkerImage) aMarker = GetTextureImage (Aspect_TOM_O, aScale);
            const Handle(Image_PixMap)& aCircle = aMarker->GetImage();

            const Standard_Size aDiffX = (anImage->SizeX() - aCircle->SizeX()) / 2;
            const Standard_Size aDiffY = (anImage->SizeY() - aCircle->SizeY()) / 2;
            for (Standard_Size aRow = 0; aRow < aCircle->SizeY(); ++aRow)
            {
              const Standard_Byte* aRowData = aCircle->Row (aRow);
              for (Standard_Size aCol = 0; aCol < aCircle->SizeX(); ++aCol)
              {
                if (aRowData[aCol] != 0)
                {
                  anImage ->ChangeValue<Image_ColorBGRA> (aDiffX + aRow, aDiffY + aCol) = aColor32;
                  anImageA->ChangeValue<Standard_Byte>   (aDiffX + aRow, aDiffY + aCol) = 255;
                }
              }
            }
            aScale -= aDelta;
          }
          break;
        }
        default:
        {
          aNewMarkerImage = GetTextureImage (theType, theScale);
          anImage = aNewMarkerImage->GetImage();
          break;
        }
      }
    }

    theMarkerSize = Max ((Standard_ShortReal )anImage->Width(),(Standard_ShortReal )anImage->Height());

    aSprite->Init (theCtx, *anImage.operator->(), Graphic3d_TOT_2D);
    if (!hadAlreadyAlpha)
    {
      if (anImageA.IsNull()
       && aSprite->GetFormat() != GL_ALPHA
       && !aNewMarkerImage.IsNull())
      {
        anImageA = aNewMarkerImage->GetImageAlpha();
      }
      if (!anImageA.IsNull())
      {
        aSpriteA->Init (theCtx, *anImageA.operator->(), Graphic3d_TOT_2D);
      }
    }
  }
  else
  {
  #if !defined(GL_ES_VERSION_2_0)
    // Creating list with bitmap for using it in compatibility mode
    GLuint aBitmapList = glGenLists (1);
    aSprite->SetDisplayList (theCtx, aBitmapList);

    Standard_Integer aWidth, aHeight, anOffset, aNumOfBytes;
    if (theType == Aspect_TOM_USERDEFINED && !theMarkerImage.IsNull())
    {
      // Reading user defined marker
      Handle(TColStd_HArray1OfByte) aBitMap = theMarkerImage->GetBitMapArray();
      Standard_Byte* aBitMapArray = new Standard_Byte[aBitMap->Length()];
      theMarkerImage->GetTextureSize (aWidth, aHeight);

      // We should pass bitmap to glBitmap with reversed line order as it draws it from
      // bottom to top
      const Standard_Integer aNumOfBytesInRow = aWidth / 8 + (aWidth % 8 ? 1 : 0);
      const Standard_Integer anUpperIndex = aBitMap->Upper();
      for (Standard_Integer aRow = 0; aRow < aHeight; aRow++)
      {
        for (Standard_Integer aByteIter = 0; aByteIter < aNumOfBytesInRow; aByteIter++)
        {
          aBitMapArray[aRow * aNumOfBytesInRow + aByteIter] =
            aBitMap->Value (anUpperIndex + 1 - (aRow + 1) * aNumOfBytesInRow + aByteIter);
        }
      }

      if (aBitMapArray != NULL)
      {
        glNewList (aBitmapList, GL_COMPILE);
        glBitmap ((GLsizei )aWidth, (GLsizei )aHeight, (GLfloat )(0.5f * aWidth), (GLfloat )(0.5f * aHeight),
                  0.f, 0.f, (const GLubyte* )aBitMapArray);
        glEndList();
      }
    }
    else
    {
      // Creating list for default marker
      const Standard_ShortReal aDelta = 0.1f;
      Standard_ShortReal aScale = theScale;
      Standard_ShortReal aLimit = 0.0f;

      glNewList (aBitmapList, GL_COMPILE);
      switch (theType)
      {
        case Aspect_TOM_O_POINT:
        {
          // draw inner point as filled rectangle
          const Standard_Integer        aSize   = theScale > 7 ? 7 : (Standard_Integer )(theScale + 0.5F);
          Handle(TColStd_HArray1OfByte) aBitMap = fillPointBitmap (aSize);
          glBitmap (aSize, aSize, (GLfloat )(0.5f * aSize), (GLfloat )(0.5f * aSize),
                    0.0f, 0.0f, &aBitMap->Array1().Value (aBitMap->Lower()));
        }
        Standard_FALLTHROUGH
        case Aspect_TOM_O_PLUS:
        case Aspect_TOM_O_STAR:
        case Aspect_TOM_O_X:
        {
          // For this type of markers we merge two base bitmaps into one
          // For example Aspect_TOM_O_PLUS = Aspect_TOM_O + Aspect_TOM_PLUS
          GetMarkerBitMapParam (Aspect_TOM_O, theScale, aWidth, aHeight, anOffset, aNumOfBytes);
          glBitmap ((GLsizei )aWidth, (GLsizei )aHeight, (GLfloat )(0.5f * aWidth), (GLfloat )(0.5f * aHeight),
                    0.f, 0.f, (const GLubyte* )&OpenGl_AspectMarker_myMarkerRaster[anOffset]);
          if (theType != Aspect_TOM_O_POINT)
          {
            GetMarkerBitMapParam (Aspect_TypeOfMarker (theType - Aspect_TOM_O_POINT), theScale, aWidth, aHeight, anOffset, aNumOfBytes);
            glBitmap ((GLsizei )aWidth, (GLsizei )aHeight, (GLfloat )(0.5f * aWidth), (GLfloat )(0.5f * aHeight),
                      0.f, 0.f, (const GLubyte* )&OpenGl_AspectMarker_myMarkerRaster[anOffset]);
          }
          break;
        }
        case Aspect_TOM_BALL:
        {
          NCollection_Vec4<Standard_Real> aColor (Standard_Real (theColor.r()),
                                                  Standard_Real (theColor.g()),
                                                  Standard_Real (theColor.b()),
                                                  Standard_Real (theColor.a()));

          // we draw a set of circles
          while (aScale >= 1.0f)
          {
            Standard_Real aHLS[3];
            Quantity_Color::RgbHls (aColor.r(), aColor.g(), aColor.b(), aHLS[0], aHLS[1], aHLS[2]);
            // 5% saturation change
            aHLS[2] *= 0.95;
            Quantity_Color::HlsRgb (aHLS[0], aHLS[1], aHLS[2], aColor.r(), aColor.g(), aColor.b());

            glColor4dv (aColor);
            GetMarkerBitMapParam (Aspect_TOM_O, aScale, aWidth, aHeight, anOffset, aNumOfBytes);
            glBitmap ((GLsizei )aWidth, (GLsizei )aHeight, 0.5f * GLfloat(aWidth), 0.5f * GLfloat(aHeight),
                      0.0f, 0.0f, (const GLubyte* )&OpenGl_AspectMarker_myMarkerRaster[anOffset]);

            aScale -= aDelta;
          }
          break;
        }
        case Aspect_TOM_RING1:
          if (aLimit == 0.0f) aLimit = aScale * 0.2f;
          Standard_FALLTHROUGH
        case Aspect_TOM_RING2:
          if (aLimit == 0.0f) aLimit = aScale * 0.5f;
          Standard_FALLTHROUGH
        case Aspect_TOM_RING3:
        {
          if (aLimit == 0.0f) aLimit = aScale * 0.8f;
          for (; aScale > aLimit && aScale >= 1.0f; aScale -= aDelta)
          {
            GetMarkerBitMapParam (Aspect_TOM_O, aScale, aWidth, aHeight, anOffset, aNumOfBytes);
            glBitmap ((GLsizei )aWidth, (GLsizei )aHeight, 0.5f * GLfloat(aWidth), 0.5f * GLfloat(aHeight),
                      0.0f, 0.0f, (const GLubyte* )&OpenGl_AspectMarker_myMarkerRaster[anOffset]);
          }
          break;
        }
        default:
        {
          GetMarkerBitMapParam (theType, theScale, aWidth, aHeight, anOffset, aNumOfBytes);
          glBitmap ((GLsizei )aWidth, (GLsizei )aHeight, 0.5f * GLfloat(aWidth), 0.5f * GLfloat(aHeight),
                    0.0f, 0.0f, (const GLubyte* )&OpenGl_AspectMarker_myMarkerRaster[anOffset]);
          break;
        }
      }
      glEndList();
    }
  #endif
  }
}

// =======================================================================
// function : spriteKeys
// purpose  :
// =======================================================================
void OpenGl_AspectsSprite::spriteKeys (const Handle(Graphic3d_MarkerImage)& theMarkerImage,
                                       Aspect_TypeOfMarker theType,
                                       Standard_ShortReal theScale,
                                       const Graphic3d_Vec4& theColor,
                                       TCollection_AsciiString& theKey,
                                       TCollection_AsciiString& theKeyA)
{
  // generate key for shared resource
  if (theType == Aspect_TOM_USERDEFINED)
  {
    if (!theMarkerImage.IsNull())
    {
      theKey  = theMarkerImage->GetImageId();
      theKeyA = theMarkerImage->GetImageAlphaId();
    }
  }
  else if (theType != Aspect_TOM_POINT
        && theType != Aspect_TOM_EMPTY)
  {
    // predefined markers are defined with 0.5 step
    const Standard_Integer aScale = Standard_Integer(theScale * 10.0f + 0.5f);
    theKey  = TCollection_AsciiString ("OpenGl_AspectMarker") + theType + "_" + aScale;
    theKeyA = theKey + "A";
    if (theType == Aspect_TOM_BALL)
    {
      unsigned int aColor[3] =
      {
        (unsigned int )(255.0f * theColor.r()),
        (unsigned int )(255.0f * theColor.g()),
        (unsigned int )(255.0f * theColor.b())
      };
      char aBytes[8];
      sprintf (aBytes, "%02X%02X%02X", aColor[0], aColor[1], aColor[2]);
      theKey += aBytes;
    }
  }
}
